头文件
对同一个对象、函数、类等的所有声明的类型都必须一致。所以,递交给编译器的源代码以及后来被连接的东西也必须一致。要达到在不同编译单位中声明的一致性,有一种不完美但却比较简单的方法,那就是将包含界面信息的头文件通过#include包含到可执行代码和/或数据定义的源程序文件里。
#include机制是一种正文操作的概念,用于将源程序片段收集到一起,形成一个提供给编译的单位(文件)。指令
#include "to_be_included"
将用文件to_be_included的内容取代这个#include所在的那一行。该文件的内容应该是C++源代码,因为编译器接着要去读它。
  如果要包含标准库文件,那么就应该使用尖括号 < 和 > 而不是引号。例如,
#include <iostream>            // 来自标准库包含目录
#include "myheader.h"          // 来自当前目录
不幸的是,在一个包含指令中,<> 或 "" 内部的空格也是有意义的:
#include < iostream >          // 将无法找到<iostream>
当一个文件被包含到某处之后,每次都需要重新去编译它,这看起来是过分奢侈了。不过,在典型情况下被包含的文件里只有声明,没有需要编译器深入分析的代码。进一步说,许多现在C++实现都提供了对头文件的某种预编译形式,以尽可能减少反复编译同一个头文件所需要的工作。
作为一种经验法则,头文件里可以包括
| 命名名字空间 | namespace N { /* ... */ } | 
| 类型定义 | struct Point { int x, y; } | 
| 模板声明 | template <class T>class Z; | 
| 模板定义 | template <class T>class V { /* ... */ }; | 
| 函数声明 | extern int strlen(const char*); | 
| 在线函数定义 | inline char get(char* p) { return *p++; } | 
| 数据声明 | extern int a; | 
| 常量定义 | const float pi = 3.141593; | 
| 枚举 | enum Light { red, yellow, green }; | 
| 名字声明 | class Matrix; | 
| 包含指令 | #include <algorithm> | 
| 宏定义 | #define VERSION12 | 
| 条件编译指令 | #ifdef __cplusplus | 
| 注释 | /* check for end of file */ | 
这种有关什么可以放入头文件的经验法则并不是语言所要求的。它只是使用#include机制来表示程序的物理结构的一种合理方式。在另一方面,头文件里绝不应该有:
| 常规的函数定义 | char get(char* p) { return *p++; } | 
| 数据定义 | int a; | 
| 聚集量(aggregate)定义 | short tb1[] = { 1, 2, 3 }; | 
| 无名名字空间 | namespace { /* ... */ } | 
| 导出的(exported)模板定义 | export template <class T>f(T t) { /* ... */ } | 
按照习惯,头文件采用后缀 .h,而包含函数或数据定义的文件用 .c 后缀。它们也因此被分别称为“.h文件”和“.c文件”。其他约定,如.C、.cxx、.cpp和.cc等也常常可以看到。你的编译器手册在这个方面可以有一些特殊东西。
上面建议只在头文件放简单常量的定义,而不放聚集量的定义,其原因是,具体实现很难避免聚集量在几个编译单位中的重复出现。进一步说,那些简单情况都是最常见的东西,因此对于生成好的代码也更重要一些。
对于#include的使用不要过于自作聪明。我的建议是,只用#include包含完整的声明和定义,而且只在全局作用域中,或在连接描述块里,或在转换老代码时在名字空间定义里这样做(9.2.2节)。与别处一样,在这里也要避免玩弄宏魔术。我最不愿意做的事情之一就是:追踪由某个名字引起的一个错误,该名字被宏替换成另一个完全不同的东西,而有关的宏定义又是出现在某个我从来也没听说过的,通过#include间接包含进来的头文件里。
🔚